﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.UI;
using System.ComponentModel;
using System.Drawing.Design;
using System.Text.RegularExpressions;

namespace TA.Turbo.Controls
{
	/// <summary>
	/// Menu strip or popup menu control.
	/// </summary>
	[ParseChildren(true, "Items")]
	public class Menu : BaseComplexControl
	{
		#region PUBLIC
		#region INIT
		/// <summary>
		/// Ctor.
		/// </summary>
		public Menu()
		{
			this.Tag = HtmlTextWriterTag.Ul;
			this.Orientation = System.Web.UI.WebControls.Orientation.Horizontal;
			this.HideTimeout = 500;

			// for menu items - initialize Click
			this.GetServerEvent<EventArgs>("Click");
		}
		#endregion
		#region PROPS
		#region DEF
		/// <summary>
		/// Props.
		/// </summary>
		protected static new Properties _clientProperties = Define(BaseComplexControl._clientProperties, 
			new BasePropertyDefinition[] {
				new ListJsonPropertyDefinition<MenuItemCollection>("Items", "It", null),
				new PropertyDefinition<int>("HideTimeout", "HT", 0),
				new EnumPropertyDefinition<DropDownTrigger>("DropDownTrigger", "DT", DropDownTrigger.Hover),
			});
		/// <summary>
		/// Props.
		/// </summary>
		public override Properties ClientProperties
		{
			get
			{
				return _clientProperties;
			}
		}
		#endregion
		/// <summary>
		/// Returns the collection of items at the top level.
		/// </summary>
		[PersistenceMode(PersistenceMode.InnerDefaultProperty)]
		public MenuItemCollection Items
		{
			get
			{
				MenuItemCollection c = GetProperty<MenuItemCollection>("Items");
				c._owner = this;
				return c;
			}
		}
		/// <summary>
		/// Returns the orientation of the top level menu.
		/// </summary>
		public System.Web.UI.WebControls.Orientation Orientation { get; set; }
		/// <summary>
		/// Length of time, in milli seconds, before a dropdown auto hides.
		/// </summary>
		public int HideTimeout
		{
			get
			{
				return this.GetProperty<int>("HideTimeout");
			}
			set
			{
				this.ViewState["HideTimeout"] = value;
			}
		}
		/// <summary>
		/// Drop down trigger for the top level menu and the default trigger for lower level menus.
		/// </summary>
		public DropDownTrigger DropDownTrigger
		{
			get
			{
				return this.GetProperty<DropDownTrigger>("DropDownTrigger");
			}
			set
			{
				this.ViewState["DropDownTrigger"] = value;
			}
		}
		#endregion
		#region METHODS
		/// <summary>
		/// Returns the current PostScenario for the specified eventName, using the menu item tree.
		/// </summary>
		/// <param name="eventName"></param>
		/// <returns></returns>
		public override PostScenario GetCurrentScenario(string name, string argument)
		{
			switch (name)
			{
				case "Click":
					return this.GetMenuItemByArgument(argument).Click.PostScenario;
			}
			return base.GetCurrentScenario(name, argument);
		}
		#endregion
		#endregion
		#region INTERNAL
		#region CONST/STATIC
		static Regex _rgxSplitArgument = new Regex(@"(?<Index>\d+)(-(?<Index>\d+))*");
		#endregion
		#region VARS
		#endregion
		#region INIT
		/// <summary>
		/// Init.
		/// </summary>
		/// <param name="e"></param>
		protected override void OnInit(EventArgs e)
		{
			base.OnInit(e);

			this.Page.Load += new EventHandler(Page_Load);
		}
		/// <summary>
		/// Registers <see cref="Script.SizePos"/>, <see cref="Script.CSS"/>, Menu.js, Menu.css, and for IE 6 and 7, Menu_IE67.css.
		/// </summary>
		protected internal override void RegisterIncludes(IncludeCollection includes)
		{
			base.RegisterIncludes(includes);

			includes.Add(Script.DropDownTrigger);
			includes.Add(Script.SizePos);
			includes.Add(Script.CSS);
			includes.Add(Script.ElementSearch);
			includes.Add(Script.MouseEnterLeaveHandler);
			includes.Add(Script.Element_AddClass);
			includes.Add(Script.String_IsNullOrEmpty);
			includes.Add(Script.Element_HasClass);
			includes.Add(Script.Element_RemoveClass);
			includes.Add(Script.String_IsNullOrEmpty);
			includes.Add(new ScriptResourceInclude("TA.Turbo.Res.JS.Menu.js", typeof(Menu)));
			includes.Add(new StyleResourceInclude("TA.Turbo.Res.CSS.Menu.css", typeof(Menu)));

			if (this.Page.Request.Browser.Browser == "IE" && this.Page.Request.Browser.MajorVersion < 8)
				includes.Add(new StyleResourceInclude("TA.Turbo.Res.CSS.Menu_IE67.css", typeof(Menu)));
		}
		void Page_Load(object sender, EventArgs e)
		{
			this.Items.PrepareArguments("");
		}
		#endregion
		#region EVENTS
		/// <summary>
		/// Raises events.
		/// </summary>
		/// <param name="name"></param>
		/// <param name="argument"></param>
		public override void RaiseEvent(string name, string argument)
		{
			switch (name)
			{
				case "Click":
					MenuItem item = GetMenuItemByArgument(argument);
					item.Click.Raise(this, EventArgs.Empty);
					break;
			}
			base.RaiseEvent(name, argument);
		}
		private MenuItem GetMenuItemByArgument(string argument)
		{
			this.Items.PrepareArguments("");

			Match mIndexes = _rgxSplitArgument.Match(argument);
			List<int> indexes = new List<int>();
			foreach (Capture c in mIndexes.Groups["Index"].Captures)
			{
				indexes.Add(int.Parse(c.Value));
			}

			int lastIndex = indexes[indexes.Count - 1];
			indexes.RemoveAt(indexes.Count - 1);

			MenuItemCollection micCurrent = this.Items;
			foreach (int index in indexes)
			{
				micCurrent = micCurrent[index].Items;
			}

			return micCurrent[lastIndex];
		}
		#endregion
		#region RENDER
		/// <summary>
		/// Adds CSS class for horizontal orientation.
		/// </summary>
		/// <param name="writer"></param>
		protected override void AddAttributesToRender(HtmlTextWriter writer)
		{
			if (this.Orientation == System.Web.UI.WebControls.Orientation.Horizontal)
			{
				this.CssClass += " turbo_menu_mhor";
			}
			else
			{
				this.CssClass = (this.CssClass ?? "").Replace(" turbo_menu_mhor", "");
			}
			base.AddAttributesToRender(writer);
		}
		/// <summary>
		/// Renders the contained menu items.
		/// </summary>
		/// <param name="writer"></param>
		protected override void RenderContents(HtmlTextWriter writer)
		{
			base.RenderContents(writer);

			foreach (MenuItem item in this.Items)
			{
				item.Render(writer);
			}
		}
		#endregion
		#endregion
	}
}
